Skip to content

refactor: improve TrackerContext type safety with structured database configs#350

Merged
josecelano merged 3 commits into
mainfrom
refactor-tracker-context-mysql-struct
Feb 16, 2026
Merged

refactor: improve TrackerContext type safety with structured database configs#350
josecelano merged 3 commits into
mainfrom
refactor-tracker-context-mysql-struct

Conversation

@josecelano

Copy link
Copy Markdown
Member

Summary

This PR refactors the TrackerContext struct to improve type safety and code clarity through three separate commits:

  1. Extract MySQL fields into MysqlTemplateConfig struct - Groups all MySQL connection parameters into a dedicated struct
  2. Extract SQLite fields into SqliteTemplateConfig struct - Creates symmetric structure for SQLite database configuration
  3. Replace database_driver String with DatabaseDriver enum - Prevents invalid database driver values at compile time

Changes

Before

pub struct TrackerContext {
    pub database_driver: String,
    pub tracker_database_name: String,
    pub mysql_host: Option<String>,
    pub mysql_port: Option<u16>,
    pub mysql_database: Option<String>,
    pub mysql_user: Option<String>,
    pub mysql_password: Option<String>,
    // ...
}

After

pub struct TrackerContext {
    pub database_driver: DatabaseDriver,
    pub sqlite: Option<SqliteTemplateConfig>,
    pub mysql: Option<MysqlTemplateConfig>,
    // ...
}

pub enum DatabaseDriver {
    Sqlite3,
    Mysql,
}

pub struct SqliteTemplateConfig {
    pub tracker_database_name: String,
}

pub struct MysqlTemplateConfig {
    pub mysql_host: String,
    pub mysql_port: u16,
    pub mysql_database: String,
    pub mysql_user: String,
    pub mysql_password: String,
}

Benefits

  • Type Safety: Enum prevents invalid database driver values at compile time
  • Clarity: Explicit that tracker_database_name is SQLite-specific
  • Consistency: Both database types use the same pattern (Option<Config>)
  • Maintainability: Database configuration is grouped logically
  • Template Compatibility: Uses #[serde(flatten)] to maintain existing template structure

Testing

  • ✅ All 21 tracker templating tests pass
  • ✅ No clippy warnings
  • ✅ All linters pass (markdown, yaml, toml, cspell, rustfmt, shellcheck)

Migration Notes

This is an internal infrastructure change. Template compatibility is maintained through #[serde(flatten)], so no changes are needed to existing templates or deployment configurations.

- Create new MysqlTemplateConfig struct with all MySQL connection parameters
- Replace 5 optional fields in TrackerContext with single Option<MysqlTemplateConfig>
- Use #[serde(flatten)] to maintain template compatibility
- Improve type safety: MySQL fields are all present or all absent
- Update tests to work with new structure
- Fix clippy doc_markdown warnings by adding backticks around MySQL/SQLite
- Create new SqliteTemplateConfig struct with tracker_database_name field
- Make database configuration symmetric: both SQLite and MySQL use Option structs
- Update TrackerContext to have optional sqlite and mysql fields
- Use #[serde(flatten)] to maintain template compatibility for both database types
- Update all tests to work with new structure
- Improve clarity: now explicit that tracker_database_name is SQLite-specific
- Create DatabaseDriver enum with Sqlite3 and Mysql variants
- Use #[serde(rename_all = "lowercase")] for template compatibility
- Improve type safety: enum prevents invalid database driver values
- Update from_config to pattern match on DatabaseConfig enum
- Update default_config to use DatabaseDriver::Sqlite3
- Update all tests to use enum variants instead of string comparisons
- Add backticks to enum variant documentation for clippy compliance
@josecelano

Copy link
Copy Markdown
Member Author

ACK 26b7830

@josecelano josecelano merged commit bebc2ef into main Feb 16, 2026
39 checks passed
josecelano added a commit that referenced this pull request Feb 16, 2026
ad2ac21 docs: [#349] document JSON output format for create command (Jose Celano)
afa7ef9 feat: [#349] add JSON output format support to create command (Jose Celano)
2ecb391 refactor: [#349] apply Strategy Pattern for output formats (SOLID) (Jose Celano)
7ce64b0 feat: [#349] add global --output-format argument (Phase 1) (Jose Celano)
67c10ff refactor: [#349] extract view layer for create command (Phase 0) (Jose Celano)

Pull request description:

  ## Summary

  Implements issue #349 - Adds machine-readable JSON output format to the `create environment` command, enabling automation workflows and CI/CD integration.

  ## Changes

  ### Architecture (5 Phases)

  **Phase 0: View Layer Extraction (67c10ff)**
  - Extracted view layer for create command following MVC pattern
  - Created `EnvironmentDetailsData` DTO and `EnvironmentDetailsView`
  - Aligned with existing provision/list/show command architecture

  **Phase 1: Global OutputFormat Argument (7ce64b0)**
  - Added `OutputFormat` enum (Text | Json) with clap integration
  - Added `--output-format` global CLI argument
  - Extended `GlobalArgs` and `ExecutionContext` with format support

  **Phase 2: Strategy Pattern Implementation (2ecb391)**
  - Separated TextView and JsonView implementations
  - Applied SOLID principles with Strategy Pattern
  - Added `Serialize` derive to EnvironmentDetailsData

  **Phase 3: Format Switching (afa7ef9)**
  - Wired output_format through ExecutionContext → Router → Controller
  - Implemented format switching with match expression
  - Added OutputFormatting error variant with detailed help

  **Phase 4: Documentation (ad2ac21)**
  - Added comprehensive "Output Formats" section to user guide
  - Documented JSON schema with field descriptions
  - Added 8+ automation examples (Shell, CI/CD, Python, multi-env)
  - Explained stdout/stderr channel separation

  ### Features

  ✅ **Two Output Formats**:
  - **Text** (default): Human-readable numbered list with progress indicators
  - **JSON**: Machine-readable structured data for automation

  ✅ **JSON Output Schema**:
  ```json
  {
    "environment_name": "my-env",
    "instance_name": "torrust-tracker-vm-my-env",
    "data_dir": "./data/my-env",
    "build_dir": "./build/my-env",
    "created_at": "2026-02-16T13:38:02.446056727Z"
  }
  ```

  ✅ **CLI Usage**:
  ```bash
  # Default text output
  torrust-tracker-deployer create environment --env-file config.json

  # JSON output for automation
  torrust-tracker-deployer create environment --env-file config.json --output-format json

  # Short form
  torrust-tracker-deployer create environment --env-file config.json -o json
  ```

  ### Quality Assurance

  - ✅ All 2230 unit tests pass
  - ✅ All 394 doctests pass
  - ✅ All linters pass (clippy, rustfmt, markdown, yaml, toml, cspell, shellcheck)
  - ✅ Pre-commit checks pass
  - ✅ E2E testing completed:
    - Default text output verified
    - JSON output validated with jq
    - Error handling tested
    - Channel separation confirmed (stdout/stderr)
  - ✅ No unused dependencies (cargo-machete clean)

  ### Documentation

  - User guide updated with comprehensive examples
  - JSON schema documented with field descriptions
  - Automation examples for Shell, CI/CD, Python
  - Output channel separation explained
  - Usage guidelines included

  ## Testing

  ### Manual Verification

  ```bash
  # Text output (default)
  ./target/release/torrust-tracker-deployer create environment \
    --env-file envs/test.json

  # JSON output
  ./target/release/torrust-tracker-deployer create environment \
    --env-file envs/test.json \
    --output-format json

  # JSON validation with jq
  ./target/release/torrust-tracker-deployer create environment \
    --env-file envs/test.json \
    -o json \
    --log-output file-only | jq .
  ```

  ### Automation Example

  ```bash
  # Extract environment details
  DATA_DIR=$(./target/release/torrust-tracker-deployer create environment \
    --env-file config.json \
    -o json \
    --log-output file-only | jq -r '.data_dir')
  ```

  ## Related

  - Closes #349
  - Part of Epic #348 - Add JSON output format support
  - Roadmap Section 12.1

  ## Breaking Changes

  None. This is a backward-compatible addition. Default behavior (text output) is preserved.

  ## Future Work

  This implementation provides the foundation for adding JSON output to other commands:
  - provision (#350)
  - show (#351)
  - list (#352)
  - status (#353)

ACKs for top commit:
  josecelano:
    ACK ad2ac21

Tree-SHA512: 47677046a60e5da16b0195c9f35c5109b020a4f715b4e23eb3a3acad70fd96198bbda64ff8b240626db5015e205031a8d6a5b6c2ce51e4748bf4206b64913529
@josecelano josecelano mentioned this pull request Feb 16, 2026
41 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant